/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cn.net.dpi.shp.util;

import ch.qos.logback.classic.sift.SiftingAppender;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.spi.AppenderAttachable;
import cn.net.dpi.shp.constants.Constants;
import cn.net.dpi.shp.log.TaskLogDiscriminator;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Optional;
import java.util.UUID;

import static cn.net.dpi.shp.constants.Constants.*;

/**
 * common utils
 */
public class TaskUtils {
    private static final Logger logger = LoggerFactory.getLogger(TaskUtils.class);

    private static final Base64 BASE64 = new Base64();

    protected TaskUtils() {
        throw new UnsupportedOperationException("Construct TaskUtils");
    }

    /**
     * build task app id
     *
     * @param tenantCode
     * @param userId
     * @param jobAlias
     * @param jobVersion
     * @param firstSubmitTime
     * @return
     */
    public static String buildTaskAppId(String tenantCode, long userId, String jobAlias, int jobVersion, LocalDateTime firstSubmitTime) {
        String uuid = StringUtils.replace(UUID.randomUUID().toString(), "-", "");
        return new StringBuilder(TASK_PREFIX)
                .append(PERIOD)
                .append(tenantCode)
                .append(PERIOD)
                .append(userId)
                .append(PERIOD)
                .append(jobAlias)
                .append(SUBTRACT_STRING)
                .append(jobVersion)
                .append(PERIOD)
                .append(firstSubmitTime.format(DateTimeFormatter.ofPattern(YYYYMMDD)))
                .append(UNDERLINE)
                .append(StringUtils.substring(uuid, 0, 5))
                .append(TASK_SUFFIX).toString();
    }

    /**
     * build job id
     *
     * @return task id format
     */
    public static String buildTaskId(LocalDateTime firstSubmitTime, String taskAppId) {
        // like TaskAppId=TASK-20230727-dpi.110.1.sat-stat-m-1.20230727_061cb.task
        String firstSubmitTimeStr = firstSubmitTime.format(DateTimeFormatter.ofPattern(Constants.YYYYMMDD));
        return String.format("%s=%s-%s-%s",
                Constants.TASK_APPID_LOG_FORMAT, Constants.TASK_LOGGER_INFO_PREFIX, firstSubmitTimeStr, taskAppId);
    }

    /**
     * directory of process execution
     *
     * @param taskAppId task App id
     * @return directory of process execution
     */
    public static String getProcessExecDir(String taskAppId, String dataBasedir) {
        String fileName = String.format("%s/exec/process/%s", dataBasedir, taskAppId);
        File file = new File(fileName);
        if (!file.exists()) {
            file.mkdirs();
        }
        return fileName;
    }

    /**
     * get task log path
     */
    public static String getTaskLogPath(LocalDateTime firstSubmitTime, String taskAppId) {
        // format /logs/YYYYMMDD/dpi.110.1.preproc-stat-m-1.20230727_061cb.task.log
        final String taskLogFileName = new StringBuilder()
                .append(taskAppId)
                .append(LOG_TAILFIX)
                .toString();
        // Optional.map will be skipped if null
        return Optional.of(LoggerFactory.getILoggerFactory())
                .map(e -> (AppenderAttachable<ILoggingEvent>) (e.getLogger("ROOT")))
                .map(e -> (SiftingAppender) (e.getAppender("TASKLOGFILE")))
                .map(e -> ((TaskLogDiscriminator) (e.getDiscriminator())))
                .map(TaskLogDiscriminator::getLogBase)
                .map(e -> Paths.get(e)
                        .toAbsolutePath()
                        .resolve(firstSubmitTime.format(DateTimeFormatter.ofPattern(Constants.YYYYMMDD)))
                        .resolve(taskLogFileName))
                .map(Path::toString)
                .orElse("");
    }

}
